`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    21:14:42 10/13/2020 
// Design Name: 
// Module Name:    alu 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module alu( input [31:0] A,
				input [31:0] B,
				input [4:0] Shamt,
				input [5:0] ALU_Func,
				output reg [31:0] res,
				output zero,
				output overflow
    );
	wire [4:0] ALU_operation = {ALU_Func[5:1]};
	wire unsign = ALU_Func[0];
	
	wire [31:0] Sum, Dif, And_Or, Xor_Nor, Slt;
	wire [31:0] SL, SR, SLv, SRv;
	wire [31:0] Lui;
	

	assign Sum = A + B;
	assign Dif = A - B;
	assign And_Or = unsign ? (A | B) : (A & B);
	assign Xor_Nor = unsign ? ~(A | B) : (A ^ B);
	assign Slt = unsign ? (A < B ? 1 : 0) : ($signed(A) < $signed(B) ? 1 : 0);
	
	assign SL = B << Shamt;
	assign SR = unsign ? (($signed(B)) >>> $signed(Shamt)) : (($signed(B)) >> $signed(Shamt));
	assign SLv = B << A;
	assign SRv = unsign ? (($signed(B)) >>> $signed(A)) : (($signed(B)) >> $signed(A));
	
	assign Lui = {B[15:0], 16'b0};
	
	always @* begin 
		case (ALU_operation)
			5'b10000: res = Sum;
			5'b10001: res = Dif;
			5'b10010: res = And_Or;
			5'b10011: res = Xor_Nor;
			5'b10101: res = Slt;
			
			5'b00000: res = SL;
			5'b00001: res = SR;
			5'b00010: res = SLv;
			5'b00011: res = SRv;
			
			5'b00100: res = Sum;
			5'b00110: res = And_Or;
			5'b00111: res = unsign ? Lui : Xor_Nor;
			5'b00101: res = Slt;

		endcase 
	end 
	
//	assign overflow = 1'b0;
	assign zero = ($signed(A) == $signed(B)) ? 1 : 0;

endmodule

